package com.hzw.saas.web.app.user.controller;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.hzw.saas.api.group.IGroupResourceService;
import com.hzw.saas.api.hpc.IHpcAccountDetailService;
import com.hzw.saas.api.hpc.IHpcAccountIncreaseService;
import com.hzw.saas.api.hpc.IHpcAccountRecordService;
import com.hzw.saas.api.hpc.IHpcAccountUserService;
import com.hzw.saas.api.hpc.bo.*;
import com.hzw.saas.api.hpc.enums.DisplayUnit;
import com.hzw.saas.api.storage.IResourceFileService;
import com.hzw.saas.api.storage.IStorageService;
import com.hzw.saas.api.storage.bo.StorageCapacityBO;
import com.hzw.saas.api.storage.enums.ResourceStatusEnum;
import com.hzw.saas.api.user.IUserRightsService;
import com.hzw.saas.api.user.bo.UserRightsBO;
import com.hzw.saas.api.workspace.IWorkRecordsService;
import com.hzw.saas.api.workspace.IWorkspaceResourceService;
import com.hzw.saas.api.workspace.bo.AWSSurplusDTO;
import com.hzw.saas.common.config.annotation.SysLog;
import com.hzw.saas.common.config.exception.DefaultSaasException;
import com.hzw.saas.common.config.query.LogicQuery;
import com.hzw.saas.common.config.util.AssertUtil;
import com.hzw.saas.common.config.util.PageParam;
import com.hzw.saas.common.security.pojo.dto.SaasUser;
import com.hzw.saas.common.security.utils.SecurityUtils;
import com.hzw.saas.common.util.MapperUtil;
import com.hzw.saas.web.app.hpc.param.HpcUsageParam;
import com.hzw.saas.web.app.user.dto.HpcAccountUsageDto;
import com.hzw.saas.web.app.user.dto.ResourcesCountDTO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiOperationSort;
import io.swagger.annotations.ApiResponse;
import jodd.util.StringUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zzl
 * @since 05/27/2021
 */
@Controller
@RequiredArgsConstructor
@Api(tags = "用户中心/数据统计")
@Validated
public class UserStatisticsController {

    private final IStorageService storageService;
    private final IResourceFileService fileService;
    private final IGroupResourceService groupResourceService;

    private final IWorkRecordsService workRecordsService;
    private final IWorkspaceResourceService workspaceResourceService;

    private final IUserRightsService userRightsService;

    private final IHpcAccountUserService hpcAccountUserService;
    private final IHpcAccountDetailService hpcAccountDetailService;
    private final IHpcAccountIncreaseService hpcAccountIncreaseService;
    private final IHpcAccountRecordService hpcAccountRecordService;

    @GetMapping("/user/resource/files/size")
    @SysLog
    @ApiOperation(value = "统计用户空间容量使用", notes = "统计用户所有资源容量使用信息")
    @ApiOperationSort(1)
    public ResponseEntity<StorageCapacityBO> getStorageCapacity() {
        String userId = SecurityUtils.getUserId();
        StorageCapacityBO storageCapacity = storageService.getStorageCapacity(userId, false);
        return ResponseEntity.ok(storageCapacity);
    }

    @GetMapping("/user/resource/files/amount")
    @SysLog
    @ApiOperation(value = "统计用户所有资源数量", notes = "统计用户所有资源数量，包括个人上传资源，HBox资源和云控制台资源")
    @ApiOperationSort(2)
    public ResponseEntity<ResourcesCountDTO> countResources() {
        String userId = SecurityUtils.getUserId();
        List<Integer> statusDeleted = ResourceStatusEnum.DELETED.groupCodes();
        int resourceNumber = fileService.countNumberByUser(userId, null, LogicQuery.ne(statusDeleted), LogicQuery.none());
        resourceNumber += (int) workspaceResourceService.countFiles(userId);
        ResourcesCountDTO resourcesCountDto = new ResourcesCountDTO(resourceNumber);
        return ResponseEntity.ok(resourcesCountDto);
    }

    @GetMapping("/user/resource/space/p/group_files/amount")
    @SysLog
    @ApiOperation(value = "统计用户群组分享资源数量", notes = "统计用户群组分享资源数量")
    @ApiOperationSort(4)
    @ApiResponse(code = 200, message = "用户已分享资源数量", response = Integer.class)
    public ResponseEntity<Integer> countSharedFiles() {
        SaasUser user = SecurityUtils.getUser();
        int resourcesCount = groupResourceService.countGroupFile(null, user.getUserId());
        return ResponseEntity.ok(resourcesCount);
    }

    // private final StorageConfig storageConfig;
    // private final IResourceFileService fileService;
    // private final IStorageService storageService;
    // private final IGroupResourceService groupResourceService;

    // @GetMapping("/user/resource/files/size")
    // @SysLog
    // @ApiOperation(value = "统计用户空间容量使用", notes = "统计用户所有资源容量使用信息")
    // @ApiOperationSort(1)
    // public ResponseEntity<StorageCapacityBO> getStorageCapacity() {
    //     SaasUser user = SecurityUtils.getUser();
    //     StorageCapacityBO storageCapacity = storageService.getStorageCapacity(user.getUserId());
    //     return ResponseEntity.ok(storageCapacity);
    // }
    //
    // @GetMapping("/user/resource/files/amount")
    // @SysLog
    // @ApiOperation(value = "统计用户所有资源数量", notes = "统计用户所有资源数量，包括个人上传资源，HBox资源和云控制台资源")
    // @ApiOperationSort(2)
    // public ResponseEntity<ResourcesCountDto> countResources() {
    //     SaasUser user = SecurityUtils.getUser();
    //     int userResourcesCount = fileService.totalCount(user.getUserId(),
    //         storageConfig.getPersonalSpaceCatalog(), ResourceStatusEnum.NORMAL.code(), FileIntegrityEnum.NORMAL.code());
    //     int workSpaceResourcesCount = (int) workspaceResourceService.countFiles(user.getUserId());
    //     int hboxResourcesCount = 0;
    //     ResourcesCountDto resourcesCountDto = new ResourcesCountDto(userResourcesCount, hboxResourcesCount, workSpaceResourcesCount);
    //     return ResponseEntity.ok(resourcesCountDto);
    // }
    //
    // @GetMapping("/user/resource/space/p/files/amount")
    // @SysLog
    // @ApiOperation(value = "统计用户个人空间资源数量", notes = "统计用户个人空间资源数量")
    // @ApiOperationSort(3)
    // @ApiResponse(code = 200, message = "用户已上传资源数量", response = Integer.class)
    // public ResponseEntity<Integer> countUserFiles() {
    //     SaasUser user = SecurityUtils.getUser();
    //     int resourcesCount = fileService.totalCount(
    //         user.getUserId(),
    //         storageConfig.getPersonalSpaceCatalog(),
    //         ResourceStatusEnum.NORMAL.code(),
    //         FileIntegrityEnum.NORMAL.code());
    //     return ResponseEntity.ok(resourcesCount);
    // }
    //
    // @GetMapping("/user/resource/space/p/group_files/amount")
    // @SysLog
    // @ApiOperation(value = "统计用户群组分享资源数量", notes = "统计用户群组分享资源数量")
    // @ApiOperationSort(4)
    // @ApiResponse(code = 200, message = "用户已分享资源数量", response = Integer.class)
    // public ResponseEntity<Integer> countSharedFiles() {
    //     SaasUser user = SecurityUtils.getUser();
    //     int resourcesCount = groupResourceService.countGroupFile(null, user.getUserId());
    //     return ResponseEntity.ok(resourcesCount);
    // }


    @GetMapping("/findHpcPowerCount")
    @ApiOperation(value = "查询当前登陆用户的增值信息")
    @ApiOperationSort(5)
    public ResponseEntity<HpcPowerCountDTO> findHpcPowerCountDTO(@RequestParam(required = false) String hpcAccountUserId) {
        List<String> accountUserIds = new ArrayList<>();
        if (StringUtil.isBlank(hpcAccountUserId)) {
            List<HpcAccountUsersBo> hpcAccountUsers = hpcAccountUserService.findHpcAccountUsers(Arrays.asList(SecurityUtils.getUser().getUserId()));
            if (CollectionUtils.isNotEmpty(hpcAccountUsers)) {
                accountUserIds.addAll(hpcAccountUsers.stream().map(HpcAccountUsersBo::getPid).collect(Collectors.toList()));
            }
        } else {
            accountUserIds.add(hpcAccountUserId);
        }

        HpcPowerCountDTO hpcPowerCountDTO = hpcAccountIncreaseService.findHpcPowerCountDTO(accountUserIds);
        return ResponseEntity.ok(hpcPowerCountDTO);
    }


    @GetMapping("/hpc/account/usage")
    @SysLog
    @ApiOperation(value = "获取超算帐号机时使用统计", notes = "获取超算帐号机时使用统计")
    @ApiOperationSort(6)
    public ResponseEntity<List<HpcAccountUsageDto>> listHpcAccountUsage(@Validated HpcUsageParam hpcUsageParam, @RequestParam(required = false) DisplayUnit displayUnit) {
        if (displayUnit == null) {
            displayUnit = DisplayUnit.D;
        }
        List<String> recordIds = dealHpcUsageParam(hpcUsageParam, false);

        AssertUtil.assertThrow("查询最大不能超过1年", DateUtil.betweenDay(hpcUsageParam.getStartDate(), hpcUsageParam.getEndDate(), false) >= 366);
        List<HpcAccountUsageBo> hpcAccountUsageBos = hpcAccountDetailService.listHpcAccountUsage(recordIds, hpcUsageParam.getStartDate(), hpcUsageParam.getEndDate(), displayUnit);

        List<HpcAccountUsageDto> hpcAccountUsageDtoList = new ArrayList<>();
        DisplayUnit finalDisplayUnit = displayUnit;
        hpcAccountUsageBos.forEach(hpcAccountUsageBo -> {
            HpcAccountUsageDto hpcAccountUsageDto = MapperUtil.nf().map(hpcAccountUsageBo, HpcAccountUsageDto.class);
            Date date = hpcAccountUsageBo.getStartDate();
            hpcAccountUsageDto.setUsage(hpcAccountUsageDto.getUsage());
            switch (finalDisplayUnit) {
                case W:
                    hpcAccountUsageDto.setDate(StrUtil.format("{}年{}周", DateUtil.format(date, "yyyy"), DateUtil.weekOfYear(date)));
                    break;
                case M:
                    hpcAccountUsageDto.setDate(DateUtil.format(date, "yyyy年MM月"));
                    break;
                case H:
                    hpcAccountUsageDto.setDate(DateUtil.format(date, "yyyy年MM月dd日HH时"));
                    break;
                case D:
                default:
                    hpcAccountUsageDto.setDate(DateUtil.formatDate(date));
                    break;
            }
            hpcAccountUsageDtoList.add(hpcAccountUsageDto);
        });

        // 核时保留2位小数并且四舍五入
        hpcAccountUsageDtoList.forEach(hpcAccountUsageDto -> {
            hpcAccountUsageDto.setUsage(NumberUtil.round(hpcAccountUsageDto.getUsage(), 2).doubleValue());
        });

        // 按日期升序
        hpcAccountUsageDtoList.sort((a, b) -> DateUtil.compare(a.getStartDate(), b.getStartDate()));

        return ResponseEntity.ok(hpcAccountUsageDtoList);
    }

    /**
     * @param hpcUsageParam
     * @param flag          是否去除当日
     * @return
     */
    private List<String> dealHpcUsageParam(@Validated HpcUsageParam hpcUsageParam, Boolean flag) {
        if (hpcUsageParam.getOffsetDays() != null) {
            if (flag) {
                hpcUsageParam.setEndDate(DateUtil.offsetDay(new Date(), -1));
            } else {
                hpcUsageParam.setEndDate(new Date());
            }
            hpcUsageParam.setStartDate(DateUtil.offsetDay(hpcUsageParam.getEndDate(), -hpcUsageParam.getOffsetDays()));
        } else if (Objects.isNull(hpcUsageParam.getStartDate()) || Objects.isNull(hpcUsageParam.getEndDate())) {
            Date today = DateUtil.date();
            if (flag) {
                today = DateUtil.offsetDay(today, -1);
            }
            hpcUsageParam.setEndDate(today);

            Integer offset = hpcUsageParam.getOffsetDays();
            if (offset == null || offset <= 0) {
                offset = -7;
            }
            hpcUsageParam.setStartDate(DateUtil.offsetDay(today, offset));
        }

        SaasUser user = SecurityUtils.getUser();
        List<String> hpcAccountRecordIds = new ArrayList<>();
        if (StringUtil.isNotBlank(hpcUsageParam.getAccountUserId())) {
            HpcAccountUserBo hpcAccountUserBo = hpcAccountUserService.getWithRecord(hpcUsageParam.getAccountUserId());
            if (hpcAccountUserBo == null || (!Objects.equals(user.getUserId(), hpcAccountUserBo.getUserId()) && hpcAccountUserBo.getIsMain() == 1)) {
                throw DefaultSaasException.build("无此帐号或无此帐号的访问权限").status(HttpStatus.BAD_REQUEST);
            }

            if (DateUtil.compare(hpcUsageParam.getStartDate(), hpcUsageParam.getEndDate()) > 0) {
                return new ArrayList<>();
            }

            if (hpcAccountUserBo.getIsMain() == 0) {
                // 获取共享帐号的startTime
                if (DateUtil.compare(hpcUsageParam.getStartDate(), hpcAccountUserBo.getCreateTime()) < 0) {
                    hpcUsageParam.setStartDate(hpcAccountUserBo.getCreateTime());
                }
                if (DateUtil.compare(hpcUsageParam.getEndDate(), hpcAccountUserBo.getSubExpireTime()) > 0) {
                    hpcUsageParam.setEndDate(hpcAccountUserBo.getSubExpireTime());
                }
            } else {
                // 主账户startTime不能大于注册时间
                String hpcAccountRecordId = hpcAccountUserBo.getHpcAccountRecordId();
                HpcAccountRecordBo hpcAccountRecordBo = hpcAccountRecordService.get(hpcAccountRecordId);
                if (DateUtil.compare(hpcUsageParam.getStartDate(), hpcAccountRecordBo.getCreateTime()) < 0) {
                    hpcUsageParam.setStartDate(hpcAccountRecordBo.getCreateTime());
                }
            }

            hpcAccountRecordIds.add(hpcAccountUserBo.getHpcAccountRecordId());
        } else {
            // 查询所有的主账号
            IPage<HpcAccountUserBo> usableListByUserIdPage = hpcAccountUserService.getUsableListByUserIdPage(new PageParam(99999, 1), user.getUserId(), 1, false);
            if (CollectionUtil.isNotEmpty(usableListByUserIdPage.getRecords())) hpcAccountRecordIds.addAll(
                usableListByUserIdPage.getRecords().stream().map(HpcAccountUserBo::getHpcAccountRecordId).collect(Collectors.toList())
            );
        }

        return hpcAccountRecordIds;
    }

    @GetMapping("/hpc/account/increase")
    @SysLog
    @ApiOperation(value = "获取超算帐号机时增值统计", notes = "获取超算帐号机时增值统计")
    @ApiOperationSort(7)
    public ResponseEntity<List<HpcAccountIncreaseUsageBo>> listHpcAccountIncreaseUsage(@Validated HpcUsageParam hpcIncreaseParam) {
        List<String> recordIds = dealHpcUsageParam(hpcIncreaseParam, true);
        List<HpcAccountIncreaseUsageBo> hpcAccountIncreaseDtos = hpcAccountDetailService.listHpcAccountIncreaseUsage(recordIds, hpcIncreaseParam.getStartDate(), hpcIncreaseParam.getEndDate());

        // 核时保留2位小数并且四舍五入
        hpcAccountIncreaseDtos.forEach(hpcAccountIncreaseDto -> {
            hpcAccountIncreaseDto.setIncrease(NumberUtil.round(hpcAccountIncreaseDto.getIncrease(), 2).doubleValue());
            hpcAccountIncreaseDto.setIncreaseTotal(NumberUtil.round(hpcAccountIncreaseDto.getIncreaseTotal(), 2).doubleValue());
        });

        return ResponseEntity.ok(hpcAccountIncreaseDtos);
    }

    @GetMapping("/hpc/account/payment/details")
    @SysLog
    @ApiOperation(value = "获取HPC账户收支明细", notes = "获取HPC账户收支明细")
    @ApiOperationSort(8)
    public ResponseEntity<IPage<HpcAccountUsageWithIncreaseBo>> listHpcAccountUsageWithIncreaseUsage(PageParam pageParam, @Validated HpcUsageParam hpcUsageParam) {
        if (pageParam == null) pageParam = new PageParam();
        List<String> recordIds = dealHpcUsageParam(hpcUsageParam, false);
        IPage<HpcAccountUsageWithIncreaseBo> hpcAccountUsageWithIncreaseDtoIPage = hpcAccountDetailService.listHpcAccountUsageWithIncreaseUsage(pageParam, recordIds, hpcUsageParam.getStartDate(), hpcUsageParam.getEndDate());
        hpcAccountUsageWithIncreaseDtoIPage.getRecords().forEach(data -> {
            data.setBalance(NumberUtil.round(data.getBalance(), 2).doubleValue());
            data.setIncreaseTotal(NumberUtil.round(data.getIncreaseTotal(), 2).doubleValue());
            data.setIncrease(NumberUtil.round(data.getIncrease(), 2).doubleValue());
            data.setUsage(NumberUtil.round(data.getUsage(), 2).doubleValue());
        });

        return ResponseEntity.ok(hpcAccountUsageWithIncreaseDtoIPage);
    }

    @GetMapping("/findAllAWSHistoryByInstId")
    @ApiOperation(value = "云控制台机时统计")
    @ApiOperationSort(9)
    public ResponseEntity<AWSSurplusDTO> findAllAWSHistoryByInstId() {
        String userId = SecurityUtils.getUser().getUserId();
        UserRightsBO userRightsByUser = userRightsService.getUserRightsByUser(userId);
        if (userRightsByUser == null) {
            AWSSurplusDTO awsSurplusDTO1 = new AWSSurplusDTO();
            awsSurplusDTO1.setAwsSurplusBalance(BigDecimal.ZERO);
            awsSurplusDTO1.setAwsTotalBalance(BigDecimal.ZERO);
            awsSurplusDTO1.setDockerRecycleDuration("0");
            awsSurplusDTO1.setEffectiveDate("");
            awsSurplusDTO1.setDockerNumber(0);
            return ResponseEntity.ok(awsSurplusDTO1);
        }
        AWSSurplusDTO awsSurplusDTO = new AWSSurplusDTO();
        awsSurplusDTO.setEffectiveDate(DateUtil.format(userRightsByUser.getAwsCoreTimeExpireTime(), "yyyy-MM-dd"));
        awsSurplusDTO.setAwsTotalBalance(new BigDecimal(userRightsByUser.getAwsCoreTime()));
        Map<String, BigDecimal> allAWSHistoryByInstId = workRecordsService.findAllAWSHistoryByUserId(userId);
        BigDecimal bigDecimal = allAWSHistoryByInstId.get(userId);
        BigDecimal divide = bigDecimal.divide(new BigDecimal("3600"), 4, 2);
        BigDecimal subtract = new BigDecimal(userRightsByUser.getAwsCoreTime()).subtract(divide);
        awsSurplusDTO.setAwsSurplusBalance(subtract.setScale(2, 2));
        awsSurplusDTO.setDockerNumber(userRightsByUser.getDockerNumber());
        String dockerRecycleDuration = userRightsByUser.getDockerRecycleDuration();
        awsSurplusDTO.setDockerRecycleDuration(dockerRecycleDuration);
        return ResponseEntity.ok(awsSurplusDTO);
    }

    @GetMapping("/hpc/account/sync/time/{hpcAccountUserId}")
    @ApiOperation(value = "获取HPC用户数据同步时间")
    @ApiOperationSort(10)
    public ResponseEntity<String> getHpcAccountSyncTime(@PathVariable String hpcAccountUserId) {
        HpcAccountUserBo hpcAccountUserBo = hpcAccountUserService.getWithRecord(hpcAccountUserId);
        String result = "未知";
        if (Objects.nonNull(hpcAccountUserBo)) {
            Date syncTime = hpcAccountDetailService.getMaxEndTimeByRecordIds(Arrays.asList(hpcAccountUserBo.getHpcAccountRecordId()));
            if (Objects.nonNull(syncTime)) result = DateUtil.formatDateTime(syncTime);
        }
        return ResponseEntity.ok(result);
    }

}
